use std::{ sync::{Arc, RwLock}};
use sqlx::mysql::{MySqlPool,MySqlPoolOptions};
use once_cell::sync::Lazy;

pub struct DatabaseService{
    pub pool:Arc<RwLock<Option<MySqlPool>>>
}

impl DatabaseService {
    pub fn new() -> Self {

       Self {
           pool:Arc::new(RwLock::new(None))
       }
    }
    pub async fn connect(&self) {
        if self.pool.read().unwrap().is_some() {
            return;
        }
        let (host,port,database,username,password,max_connect) = {
            let db = crate::global_config!(db);
            (db.get_host(),db.get_port(),db.get_database(),db.get_username(),db.get_password(),db.get_max_connection())
        };
        let connect_string = format!("mysql://{}:{}@{}:{}/{}",username,password,host,port,database);
        // println!("{}",connect_string);
        let pool = MySqlPoolOptions::new().max_connections(max_connect).connect(&connect_string).await.unwrap();
        self.pool.write().unwrap().replace(pool);
    }
}

pub static GLOBAL_DATABASE:Lazy<DatabaseService> = Lazy::new(||{
    let db = DatabaseService::new();
    db
});
#[macro_export]
macro_rules! db_init {
    () => {
        $crate::services::database_service::GLOBAL_DATABASE.connect()
    };
}
#[macro_export]
macro_rules! get_db_pool {
    () => {
        $crate::services::database_service::GLOBAL_DATABASE.pool.read().unwrap().as_ref().clone().unwrap()
    };
}
#[cfg(test)]
mod tests {
    use super::*;

    #[actix_rt::test]
    async fn test_db_connect() {
        &GLOBAL_DATABASE.connect().await;
        let row:(i64,) = sqlx::query_as("SELECT ?").bind(150_i64).fetch_one( get_db_pool!()).await.unwrap();
        assert_eq!(row.0,150_i64);
    }
}